package com.piece.file.client.ftp;

import com.piece.core.framework.exception.ErrorCode;
import com.piece.core.framework.exception.FrameWorkException;
import com.piece.core.framework.util.file.FileUtil;
import com.piece.core.framework.util.security.coder.MD5Coder;
import com.piece.file.client.AbstractFileClient;
import com.piece.file.model.TbSysFile;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import java.io.*;
import java.util.List;

/**
 * Ftp文件客户端
 */
@Slf4j
public class FtpFileClient extends AbstractFileClient<FtpFileClientConfig> {

    private FTPClient client;

    public FtpFileClient(String name, FtpFileClientConfig config) {
        super(name, config);
    }

    @Override
    protected void doInit() {
        if (!config.getBasePath().endsWith(File.separator)) {
            config.setBasePath(config.getBasePath() + File.separator);
        }

        // 初始化Ftp对象
        this.client = new FTPClient();
    }

    private boolean connect() {
        try {
            // 连接FTP服务器
            client.connect(config.getDomain(), config.getPort());
            // 登录
            client.login(config.getAccessKey(), config.getAccessSecret());
            int reply = client.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                client.disconnect();
                return false;
            }

            // 设置为被动模式
            client.enterLocalPassiveMode();
            // 设置上传文件的类型为二进制类型
            client.setFileType(FTP.BINARY_FILE_TYPE);
            // 设置文件编码
            client.setControlEncoding("UTF-8");
        } catch (IOException e) {
            log.error("获取Ftp连接异常：{}", e.getMessage());
        }
        return true;
    }

    private void disconnect() {
        if (null != client && client.isConnected()) {
            try {
                client.disconnect();
            } catch (IOException e) {
                log.error("关闭FTP连接异常：{}", e.getMessage());
            }
        }
    }

    @Override
    public TbSysFile writeToServerStore(byte[] bytes, String path, String name, String md5, boolean stat) throws Exception {
        TbSysFile file = new TbSysFile();
        file.setMd5(md5);
        try {
            String workDirectory = path;
            if (!path.startsWith(config.getBasePath())) {
                workDirectory = config.getBasePath() + path;
            }

            List<TbSysFile> existFiles = tbSysFileService.findFileByMd5(md5);
            if (null != existFiles && existFiles.size() > 0) {
                file.setServerId("ftp");
                file.setServerFileName(existFiles.get(0).getServerFileName());
                file.setServerPath(existFiles.get(0).getServerPath());
                return file;
            }

            if (!connect()) {
                throw new FrameWorkException(ErrorCode.UPLOAD);
            }

            // 切换到上传目录
            if (!client.changeWorkingDirectory(workDirectory)) {
                // 如果目录不存在创建目录
                String[] dirs = workDirectory.split(File.separator);
                String tempPath = "";
                for (String dir : dirs) {
                    if (null == dir || "".equals(dir)) continue;
                    tempPath += File.separator + dir;
                    if (!client.changeWorkingDirectory(tempPath)) {
                        if (!client.makeDirectory(tempPath)) {
                            return null;
                        } else {
                            client.changeWorkingDirectory(tempPath);
                        }
                    }
                }
            }
            // 上传文件
            if (!client.storeFile(name, new ByteArrayInputStream(bytes))) {
                throw new FrameWorkException(ErrorCode.UPLOAD);
            }

            file.setServerId("ftp");
            file.setServerFileName(name);
            file.setServerPath(workDirectory);
            client.logout();
            return file;
        } catch (IOException e) {
            log.error("上传FTP文件异常：{}", e.getMessage());
            throw new FrameWorkException(ErrorCode.UPLOAD);
        } finally {
            disconnect();
        }
    }

    @Override
    public InputStream downloadFile(TbSysFile file) throws Exception {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            String remotePath = file.getServerPath();
            String fileName = file.getServerFileName();
            if (connect()) {
                // 转移到FTP服务器目录
                client.changeWorkingDirectory(remotePath);
                FTPFile[] fs = client.listFiles();
                for (FTPFile f_file : fs) {
                    if (f_file.getName().equals(fileName)) {
                        client.retrieveFile(f_file.getName(), os);
                        break;
                    }
                }
                client.logout();
                byte[] bytes = os.toByteArray();
                return new ByteArrayInputStream(bytes);
            }
        } catch (IOException e) {
            log.error("下载FTP文件异常：{}", e.getMessage());
            throw new FrameWorkException(ErrorCode.DOWNLOAD);
        } finally {
            disconnect();
            os.close();
        }

        return null;
    }

    @Override
    public void updateFile(TbSysFile file) {
        try {
            // 删除原文件
            deleteServerFile(file);
            byte[] bytes = FileUtil.toByte(file.getFileInputStream());
            String md5 = MD5Coder.md5File(bytes);
            // 重新上传文件
            writeToServerStore(bytes, file.getServerPath(), file.getServerFileName(), md5, false);
        } catch (Exception e) {
            log.error("更新FTP文件异常：{}", e.getMessage());
            throw new FrameWorkException(new ErrorCode(e.getMessage()));
        }
    }

    @Override
    public void deleteFile(TbSysFile file) throws Exception {
        deleteTbSysFile(file);
        deleteServerFile(file);
    }

    private void deleteServerFile(TbSysFile file) {
        if (checkMd5(file)) {
            return;
        }

        try {
            if (!connect()) {
                throw new FrameWorkException(ErrorCode.DELETE);
            }

            String remotePath = file.getServerPath();
            String fileName = file.getServerFileName();
            // 转移到FTP服务器目录
            client.changeWorkingDirectory(remotePath);
            FTPFile[] fs = client.listFiles();
            for (FTPFile f_file : fs) {
                if (f_file.getName().equals(fileName)) {
                    client.deleteFile(remotePath + File.separator + fileName);
                    break;
                }
            }

            client.logout();
        } catch (Exception e) {
            log.error("删除FTP文件异常：{}", e.getMessage());
            throw new FrameWorkException(ErrorCode.DELETE);
        } finally {
            disconnect();
        }
    }
}
